{
 "cells": [
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Face Quality Assessment for Face Verification in Video \n",
    "https://pdfs.semanticscholar.org/2c0a/caec54ab2585ff807e18b6b9550c44651eab.pdf?_ga=2.118968650.2116578973.1552199994-98267093.1547624592"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "pwd"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "WARNING:tensorflow:From D:\\Almaatech\\face\\face-quality-metrics\\detection\\mtcnn\\detect_face.py:210: calling reduce_max (from tensorflow.python.ops.math_ops) with keep_dims is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "keep_dims is deprecated, use keepdims instead\n",
      "WARNING:tensorflow:From D:\\Almaatech\\face\\face-quality-metrics\\detection\\mtcnn\\detect_face.py:212: calling reduce_sum (from tensorflow.python.ops.math_ops) with keep_dims is deprecated and will be removed in a future version.\n",
      "Instructions for updating:\n",
      "keep_dims is deprecated, use keepdims instead\n"
     ]
    }
   ],
   "source": [
    "import tensorflow as tf\n",
    "from detection.mtcnn import detect_face\n",
    "with tf.Graph().as_default():\n",
    "    sess = tf.Session()\n",
    "    pnet, rnet, onet = detect_face.create_mtcnn(sess, None)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import cv2\n",
    "import numpy as np\n",
    "\n",
    "\n",
    "img = cv2.imread('alireza.jpg')\n",
    "gray = cv2.imread('alireza.jpg', 0)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [],
   "source": [
    "minsize = 20 # minimum size of face\n",
    "threshold = [ 0.6, 0.7, 0.7 ]  # three steps's threshold\n",
    "factor = 0.709 # scale factor\n",
    "\n",
    "#Size Parameter\n",
    "lower_threshold = 100\n",
    "upper_threshold = 200\n",
    "\n",
    "bounding_boxes, points = detect_face.detect_face(img, minsize, pnet, rnet, onet, threshold, factor)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Illumination "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def illumination(gray):\n",
    "    # length of R available  range  of  gray  intensities  excluding  5%  of  the darkest  and  brightest  pixel\n",
    "    sorted_gray = np.sort(gray.ravel())\n",
    "    l = len(sorted_gray)\n",
    "    cut_off_idx = l * 5 // 100\n",
    "    r = sorted_gray[l-cut_off_idx] - sorted_gray[cut_off_idx]\n",
    "    return np.round(r / 255, 2)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "illumination(gray)"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Sharpness"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def get_contour(pts):\n",
    "    return np.array([[pts[i], pts[5 + i]] for i in  [0, 1, 4, 3]], np.int32).reshape((-1,1,2))\n",
    "\n",
    "def get_mask(image, contour):\n",
    "    mask = np.zeros(image.shape[0:2],dtype=\"uint8\")\n",
    "    cv2.drawContours(mask, [contour], -1, 255, -1)\n",
    "    return mask"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": [
    "def sharpness(img, landmark):\n",
    "    contour = get_contour(landmark)\n",
    "    mask = get_mask(img, contour) #1-channel mask\n",
    "    mask = np.stack((mask,)*3, axis=-1) #3-channel mask\n",
    "    mask[mask == 255] = 1 # convert 0 and 255 to 0 and 1\n",
    "    laplacian = cv2.Laplacian(img,cv2.CV_64F)\n",
    "    edges = laplacian[mask.astype(bool)]\n",
    "    return np.round(edges.var() / 255 , 2)\n",
    "\n",
    "sharpness(img, points[:,0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Facial Symmetry"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "from skimage.feature import hog\n",
    "\n",
    "def symmetry(img, landmark, bounding_box):\n",
    "    x1, y1, x2, y2 = int(min(bounding_box[0], min(landmark[:5]))), \\\n",
    "        int(min(bounding_box[1], min(landmark[5:]))), \\\n",
    "        int(max(bounding_box[2], max(landmark[:5]))), \\\n",
    "        int(max(bounding_box[3], max(landmark[5:])))\n",
    "    \n",
    "    landmark = np.array([[landmark[i], landmark[5 + i]] for i in  range(5)], np.int32).reshape((-1,1,2))\n",
    "    contour = landmark[:, 0] - [[x1, y1]]\n",
    "    \n",
    "    face = img[y1: y2, x1: x2].copy()\n",
    "    face_flip = cv2.flip(face, 1)\n",
    "    \n",
    "    fd_face, hog_face = hog(face, orientations=8, pixels_per_cell=(16, 16),\n",
    "                    cells_per_block=(1, 1), visualize=True, multichannel=True)\n",
    "    fd_flip, hog_flip = hog(face_flip, orientations=8, pixels_per_cell=(16, 16),\n",
    "                    cells_per_block=(1, 1), visualize=True, multichannel=True)\n",
    "    \n",
    "    \n",
    "    d = np.zeros(len(contour))\n",
    "    for i in range(len(d)):\n",
    "        d[i] = min(hog_face[contour[i, 1], contour[i, 0]], hog_flip[contour[i, 1], contour[i, 0]])\n",
    "    \n",
    "    return np.average(d)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\users\\bahar\\appdata\\local\\programs\\python\\python35\\lib\\site-packages\\skimage\\feature\\_hog.py:150: skimage_deprecation: Default value of `block_norm`==`L1` is deprecated and will be changed to `L2-Hys` in v0.15. To supress this message specify explicitly the normalization method.\n",
      "  skimage_deprecation)\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "0.02465394288301468"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "symmetry(img, points, bounding_boxes[0])"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": [
    "# Face Size"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [],
   "source": [
    "def size(img):\n",
    "    x = min(img.shape[0], img.shape[1])\n",
    "    \n",
    "    if (x > upper_threshold):\n",
    "        return 1\n",
    "    elif (x < lower_threshold):\n",
    "        return 0\n",
    "    else:\n",
    "        return (x - lower_threshold) / (upper_threshold - lower_threshold)\n",
    "    \n",
    "    print(x)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "1"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "size(img)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.5.4"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
